package com.rabbit.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaFoxUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.rabbit.constant.DeviceType;
import com.rabbit.constant.SecurityConstant;
import com.rabbit.db.entity.User;
import com.rabbit.mapper.UserMapper;
import com.rabbit.redis.service.RedisService;
import com.rabbit.service.TokenService;
import com.rabbit.util.StpCustomerUtil;
import com.rabbit.vo.req.TokenReq;
import com.rabbit.vo.res.TokenRes;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <h1>Token管理业务实现类</h1>
 *
 * @author zjw
 * @date 2022/1/19 9:31
 */
@Service
public class TokenServiceImpl implements TokenService {

    @Resource
    private UserMapper userMapper;

    @Resource
    private RedisService redisService;

    @Override
    public PageInfo<TokenRes> queryTokenList(TokenReq tokenReq) {
        String keyword = "";
        if (StringUtils.hasText(tokenReq.getLoginAccount())) {
            User user = userMapper.selectOne(User.builder().loginAccount(tokenReq.getLoginAccount()).build());
            keyword = user != null ? user.getUserId().toString() : "-1";
        }
        int count = StpUtil.searchTokenSessionId(keyword, -1, 99).size();
        int start = 0;
        if (tokenReq.getPage() != 1) {
            start = (tokenReq.getPage() - 1) * tokenReq.getLimit();
        }
        String key = SecurityConstant.TOKEN_HEADER + ":login:token-session:*" + keyword + "*";
        if (tokenReq.getDevice().equals(DeviceType.APP)) {
            key = SecurityConstant.TOKEN_HEADER + ":customer:token-session:*" + keyword + "*";
        }
        Set<String> keys = redisService.keys(key);
        List<String> list = new ArrayList<>(keys);
        List<String> sessions = SaFoxUtil.searchList(list, start, 99);
        List<String> tokenSessions = redisService.multiGet(sessions);

        List<TokenRes> tokens = tokenSessions.stream().map(e -> tokenSession2TokenRes(e, tokenReq)).filter(e -> {
            boolean flag = true;
            if (StringUtils.hasText(tokenReq.getLoginAccount())) {
                flag = Objects.equals(tokenReq.getLoginAccount(), e.getLoginAccount());
            }
            return flag;
        }).collect(Collectors.toList());
        int pages = count % tokenReq.getLimit() == 0 ? count / tokenReq.getLimit() : count / tokenReq.getLimit() + 1;
        return new PageInfo<>(tokens, pages);
    }

    @Override
    public void deleteToken(TokenReq tokenReq) {
        if (DeviceType.PC.equals(tokenReq.getDevice())) {
            StpUtil.logoutByTokenValue(tokenReq.getToken());
        } else {
            StpCustomerUtil.logoutByTokenValue(tokenReq.getToken());
        }
    }

    private TokenRes tokenSession2TokenRes(String json, TokenReq tokenReq) {
        final TokenRes tokenRes = TokenRes.builder().build();
        JSONObject jsonObject = JSONObject.parseObject(json);
        JSONObject dataMap = (JSONObject) jsonObject.get("dataMap");
        JSONObject loginUserMap = (JSONObject) dataMap.get(SecurityConstant.LOGIN_USER);

        // token
        String token = jsonObject.getString("id");
        token = token.substring(token.lastIndexOf(":") + 1);
        tokenRes.setToken(token);

        // Device
        tokenRes.setDevice(tokenReq.getDevice());

        // outTime
        Long createTime = (Long) jsonObject.get("createTime");
        LocalDateTime localDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(createTime), ZoneId.systemDefault());
        int minusDays = tokenReq.getDevice().equals(DeviceType.PC) ? -30 : -7;
        String outTime = localDateTime.minusDays(minusDays).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        tokenRes.setOutTime(outTime);

        // 登录人姓名、账号、角色名
        StringBuilder roleName = new StringBuilder("");
        if (tokenRes.getDevice().equals(DeviceType.APP)) {
            loginUserMap = (JSONObject) dataMap.get(SecurityConstant.LOGIN_CUSTOMER);
        }
        tokenRes.setLoginAccount(loginUserMap.getString("loginAccount"));
        tokenRes.setUserName(loginUserMap.getString("userName"));

        JSONArray loginUserRoles = (JSONArray) dataMap.get(SecurityConstant.LOGIN_ROLE);
        if (loginUserRoles != null) {
            ((JSONArray) loginUserRoles.get(1)).forEach(e -> {
                roleName.append(e).append(",");
            });
            tokenRes.setRoleName(roleName.substring(0, roleName.length() - 1));
        }
        return tokenRes;
    }
}
